/*
 * WorkerManager.cpp
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#include "../../../include/core/worker/WorkerManager.h"

WorkerManager * WorkerManager::manager;
bool WorkerManager::initialized;
vector<double> WorkerManager::original_configuration;
CellModel * WorkerManager::template_cell_model;
SubstrateModel * WorkerManager::template_substrate_model;
Comparator * WorkerManager::template_comparator;
unsigned int WorkerManager::n_threads;

WorkerManager::WorkerManager(){}

WorkerManager * WorkerManager::getInstance(){
	if(manager==0){
		if(initialized == true){
			manager = new WorkerManager();
		}
		else{
			cout << "WorkerManager not initialized. Exiting." << endl;
			exit(0);
		}
	}
	return manager;
}

void WorkerManager::initialize(CellModel * TEMPLATE_CELL_MODEL, SubstrateModel * TEMPLATE_SUBSTRATE_MODEL, Comparator * TEMPLATE_COMPARATOR, unsigned int N_THREADS){
		initialized = true;
		template_cell_model = TEMPLATE_CELL_MODEL;
		template_substrate_model = TEMPLATE_SUBSTRATE_MODEL;
		template_comparator = TEMPLATE_COMPARATOR;
		original_configuration = template_cell_model->get_final_configuration();
		n_threads = N_THREADS;
}

Worker * WorkerManager::findOrCreateFreeWorker(){
	if(worker.size()<n_threads)
	{
		Worker * w = new Worker(template_cell_model, template_substrate_model, template_comparator, -1);
		worker.push_back(w);
		w->lock();
		cout << "Created new worker." << endl;
		return w;
	}
	else
	{
		while(true)
		{
			for(unsigned int i=0;i<worker.size();i++){
				if(!worker[i]->isLocked()) {
					worker[i]->lock();
					return worker[i];
				}
			}
			sleep(1);
		}
	}
}

Worker * WorkerManager::getWorker(vector<double> parameters, int ID){
	Worker * w = findOrCreateFreeWorker();
	w->init(parameters, original_configuration, ID);
	return w;
}

Worker * WorkerManager::getWorker(vector<double> parameters, vector<double> initial_configuration, int ID){
	Worker * w = findOrCreateFreeWorker();
	w->init(parameters, initial_configuration, ID);
	return w;
}
